package engine;

public abstract class Engine implements Runnable {

    /** Types interne */
    public enum State { STARTED, STOPPED, SUSPENDED };

    /** Attributs */
    private State m_state;
    private Thread m_thread;

    /** Constructeurs */
    public Engine() {
        m_state = State.STOPPED;
        m_thread = new Thread(this);
    }

    /** Accesseurs */
    public State getState() { return m_state; }

    /** Mutateurs */
    private synchronized void setState(State state) {
        m_state = state;
        notify();
    }

    /** Methodes */
    public void start() {
        if (m_state == State.STOPPED) {
            m_state = State.STARTED;
            m_thread.start();
        }
        else setState(State.STARTED);
    }
    
    public void run() {
        begin();
        while (m_state != State.STOPPED) {
            if (m_state == State.SUSPENDED) waitForResume(); 
            else iteration();
        }
        end();
    }
	
    public void stop() {
        if (m_state == State.STARTED || m_state == State.SUSPENDED) {
            setState(State.STOPPED);
            try { m_thread.join(); }
            catch (InterruptedException e) {}
        }
    }

    public void suspend() {
        if (m_state == State.STARTED) setState(State.SUSPENDED);
    }

    private synchronized void waitForResume() {
        while (m_state != State.STARTED && m_state != State.STOPPED) 
            try { wait(); }
            catch (InterruptedException e) {}
    }

    protected abstract void begin();

    protected abstract void iteration();

    protected abstract void end();

}
